use std::fmt::{Debug, Formatter};
use std::ops::Range;
use std::pin::Pin;
use std::sync::Arc;

pub use eusb::prelude::*;
pub use eusb::prelude::PipConfig;
use futures::{FutureExt, Stream};
use futures::future::BoxFuture;
use futures_util::stream::Map;
use log::debug;

use crate::define::*;
pub use crate::define::SweepStyle;
use crate::error::*;

mod define;

pub mod error;

const HACKRF_USB_VID: u64 = 0x1d50;
const HACKRF_JAWBREAKER_USB_PID: u64 = 0x604b;
const HACKRF_ONE_USB_PID: u64 = 0x6089;
const RAD1O_USB_PID: u64 = 0xcc15;

pub const BYTES_PER_BLOCK: u32 = 16384;
const MAX_SWEEP_RANGES: u32 = 10;
const SWEEP_INFO_LEN: usize = 14;
const SAMPLES_PER_BLOCK: usize = 8192;
const BLOCKS_PER_TRANSFER: usize = BYTES_PER_BLOCK as usize / SAMPLES_PER_BLOCK;

const FREQ_ONE_MHZ: u64 = 1000000;
const FREQ_MAX_MHZ: u64 = 7250;

pub struct SweepData {
    pub ts: u64,
    pub freq: u64,
    data: Vec<u8>,
}

impl SweepData {
    pub fn data(&self) -> &[u8] {
        &self.data[SWEEP_INFO_LEN..]
    }
}


pub type SweepStream = Pin<Box<dyn Stream<Item=SweepData> + Send>>;


fn is_hackrf(pid: u16) -> bool {
    let pid = pid as u64;

    pid == HACKRF_JAWBREAKER_USB_PID
        || pid == HACKRF_ONE_USB_PID
        || pid == RAD1O_USB_PID
}

#[derive(Clone)]
pub struct HackRF {
    pub usb: Arc<UsbDevice>,
}

impl Debug for HackRF {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, r"
HackRF:
  pid: {:04x}
  vid: {:04x}
  ",
               self.usb.device_descriptor().unwrap().idProduct, self.usb.device_descriptor().unwrap().idVendor)
    }
}


fn new_request(cmd: Cmd) -> ControlTransferRequest {
    ControlTransferRequest {
        recipient: UsbControlRecipient::Device,
        request: cmd.0,
        value: 0,
        index: 0,
        timeout: Default::default(),
        transfer_type: UsbControlTransferType::Vendor,
    }
}

impl HackRF {
    pub async fn open_one() -> Result<HackRF> {
        let mut list = UsbDevice::list()?;
        let mut i = -1;

        for (index, device) in list.iter().enumerate() {
            if is_hackrf(device.device_descriptor().unwrap().idProduct) {
                i = index as i32;
                break;
            }
        }
        if i >= 0 {
            let device = list.remove(i as usize);
            Self::new(device).await
        } else {
            Err(HackRFError::NoDevice)
        }
    }

    pub async fn device_list() -> Result<Vec<HackRF>> {
        let mut list = UsbDevice::list()?;
        let mut out = Vec::with_capacity(list.len());

        while let Some(device) = list.pop() {
            if is_hackrf(device.device_descriptor().unwrap().idProduct) {
                let rf = HackRF::new(device).await?;
                out.push(rf);
            }
        }
        Ok(out)
    }

    pub async fn open_by_sn(sn: String) -> Result<HackRF> {
        let mut list = UsbDevice::list()?;
        let want = sn.trim();
        let mut i = None;

        for (index, device) in list.iter().enumerate() {
            match device.serial_number() {
                Ok(d_sn) => {
                    let sn_str = d_sn.trim();
                    if want == sn_str {
                        i = Some(index);
                        break;
                    }
                }
                Err(_) => {}
            }
        }
        if let Some(i) = i {
            let device = list.remove(i);
            return Self::new(device).await;
        }

        Err(HackRFError::NoDevice)
    }

    async fn new(device: UsbDevice) -> Result<Self> {
        device.set_config_by_value(1)?;
        let s = Self {
            usb: Arc::new(device),
        };
        s.set_mode_off().await?;
        Ok(s)
    }


    fn control_transfer_out(&self, request: ControlTransferRequest, data: Vec<u8>) -> BoxFuture<Result<()>> {
        let f = self.usb.control_transfer_out(request, &data);
        let data_len = data.len();
        async move {
            let n = f.await?;
            if n < data_len {
                return Err(HackRFError::Usb(format!("usb len error: {}", n)));
            }
            Ok(())
        }.boxed()
    }
    fn control_transfer_in(&self, request: ControlTransferRequest, capacity: usize) -> BoxFuture<Result<Vec<u8>>> {
        let usb = self.usb.clone();
        async move {
            Ok(usb.control_transfer_in(request, capacity).await?)
        }.boxed()
    }
    pub fn sn(&self) -> Result<String> {
        let sn = self.usb.serial_number()?;
        Ok(sn)
    }

    pub fn version_string_read(&self, len: usize) -> BoxFuture<Result<Vec<u8>>> {
        let request = new_request(Cmd::VERSION_STRING_READ);
        self.control_transfer_in(request, len)
    }

    fn set_transceiver_mode(&self, mode: TransceiverMode) -> BoxFuture<Result<()>> {
        let mut request = new_request(Cmd::SET_TRANSCEIVER_MODE);
        request.value = mode.0;
        self.control_transfer_out(request, vec![])
    }

    pub async fn init_sweep(&self, frequency_list: Vec<Range<u32>>, num_bytes: u32, step_width: u32, offset: u32, style: SweepStyle) -> Result<()> {
        let mut data = vec![];

        if num_bytes % BYTES_PER_BLOCK != 0 {
            return Err(HackRFError::ParamErr(format!("num_bytes ({})", num_bytes)));
        }

        if BYTES_PER_BLOCK > num_bytes {
            return Err(HackRFError::ParamErr(format!("num_bytes {} < {}", num_bytes, BYTES_PER_BLOCK)));
        }

        if step_width < 1 {
            return Err(HackRFError::ParamErr(format!("step_width {} < 1", step_width)));
        }

        data.push((step_width & 0xff) as u8);
        data.push(((step_width >> 8) & 0xff) as u8);
        data.push(((step_width >> 16) & 0xff) as u8);
        data.push(((step_width >> 24) & 0xff) as u8);
        data.push((offset & 0xff) as u8);
        data.push(((offset >> 8) & 0xff) as u8);
        data.push(((offset >> 16) & 0xff) as u8);
        data.push(((offset >> 24) & 0xff) as u8);
        data.push(style as u8);
        for range in frequency_list {
            data.push((range.start & 0xff) as u8);
            data.push(((range.start >> 8) & 0xff) as u8);
            data.push((range.end & 0xff) as u8);
            data.push(((range.end >> 8) & 0xff) as u8);
        }
        let mut request = new_request(Cmd::INIT_SWEEP);
        request.value = (num_bytes & 0xffff) as u16;
        request.index = ((num_bytes >> 16) & 0xffff) as u16;

        self.usb.control_transfer_out(request, &data).await?;

        Ok(())
    }

    pub async fn start_sweep_channel(&self, mut pip_config: PipConfig) -> Result<SweepStream> {
        self.set_transceiver_mode(TransceiverMode::RX_SWEEP).await?;
        pip_config.package_size = TRANSFER_BUFFER_SIZE;
        let rx = self.usb.bulk_transfer_pip_in(1, pip_config)?;
        let stream = rx.map(|x| {
            let bytes_num = BYTES_PER_BLOCK as usize;
            let mut list = Vec::with_capacity(x.len() / bytes_num);
            for i in 0..list.capacity() {
                let begin = i * bytes_num;
                let x = &x[begin..begin + bytes_num];
                
                if !(x[0] == 0x7F && x[1] == 0x7F) {
                    continue;
                }
                
                
                let freq = (x[9] as u64) << 56
                    | (x[8] as u64) << 48
                    | (x[7] as u64) << 40
                    | (x[6] as u64) << 32
                    | (x[5] as u64) << 24
                    | (x[4] as u64) << 16
                    | (x[3] as u64) << 8
                    | (x[2] as u64) 
                    ;
                let ts = (x[13] as u64) << 24
                    | (x[12] as u64) << 16
                    | (x[11] as u64) << 8
                    | (x[10] as u64)
                    ;

                const FREQ_MAX: u64 = FREQ_ONE_MHZ * FREQ_MAX_MHZ;
                
                if freq > FREQ_MAX { 
                    continue;
                }
                
                list.push(
                    SweepData {
                        ts,
                        freq,
                        data: x[SWEEP_INFO_LEN..].to_vec(),
                    });
            }
            futures::stream::iter(list)
        }).flatten();
        Ok(Box::pin(stream))
    }

    pub async fn start_rx_channel(&self, mut pip_config: PipConfig) -> Result<EndpointPipIn> {
        self.set_transceiver_mode(TransceiverMode::RECEIVE).await?;
        pip_config.package_size = TRANSFER_BUFFER_SIZE;
        let rx = self.usb.bulk_transfer_pip_in(1, pip_config)?;
        Ok(rx)
    }

    pub fn set_mode_off(&self) -> BoxFuture<Result<()>> {
        self.set_transceiver_mode(TransceiverMode::OFF)
    }

    fn set_baseband_filter_bandwidth(&self, bandwidth_hz: usize) -> BoxFuture<Result<()>> {
        let mut request = new_request(Cmd::BASEBAND_FILTER_BANDWIDTH_SET);
        let bandwidth_hz = compute_baseband_filter_bw(bandwidth_hz);
        request.value = (bandwidth_hz & 0xffff) as u16;
        request.index = (bandwidth_hz >> 16) as u16;
        debug!("set baseband: {}", bandwidth_hz);
        self.control_transfer_out(request, vec![])
    }

    fn set_sample_rate_manual(&self, freq_hz: u32, divider: u32) -> BoxFuture<Result<()>> {
        let mut data = freq_hz.to_le_bytes().to_vec();
        let mut divider_bytes = divider.to_le_bytes().to_vec();
        data.append(&mut divider_bytes);
        let request = new_request(Cmd::SAMPLE_RATE_SET);

        debug!("set sample rate: {}", freq_hz / divider);
        let s = self.clone();

        async move {
            s.control_transfer_out(request, data).await?;
            let freq = 0.75 * freq_hz as f64 / (divider as f64);
            s.set_baseband_filter_bandwidth(freq as usize).await?;
            Ok(())
        }.boxed()
    }


    pub fn set_sample_rate(&self, freq_hz: f64) -> BoxFuture<Result<()>> {
        self.set_sample_rate_manual(freq_hz as u32, 1)
    }


    pub async fn set_freq(&self, freq_hz: f64) -> Result<()> {
        let freq_hz = freq_hz as u64;

        let l_freq_mhz = (freq_hz / ONE_MHZ) as u32;
        let l_freq_hz = (freq_hz % ONE_MHZ) as u32;

        let mut data = Vec::with_capacity(8);
        let mut data1 = l_freq_mhz.to_le_bytes().to_vec();
        let mut data2 = l_freq_hz.to_le_bytes().to_vec();
        data.append(&mut data1);
        data.append(&mut data2);

        let request = new_request(Cmd::SET_FREQ);
        debug!("set freq: {}.{} MHz", l_freq_mhz, l_freq_hz);
        self.control_transfer_out(request, data).await
    }

    pub async fn set_lna_gain(&self, value: u32) -> Result<()> {
        debug!("set lna gain: {}", value);

        let mut value = value as u16;
        if value > 40 {
            return Err(HackRFError::ParamErr("lna >40".to_string()));
        }
        value &= !0x07;

        let mut request = new_request(Cmd::SET_LNA_GAIN);
        request.index = value;
        let data = self.control_transfer_in(request, 1).await?;

        if data[0] == 0 {
            Err(HackRFError::ParamErr("lna set fail".to_string()))
        } else {
            Ok(())
        }
    }

    pub async fn set_vga_gain(&self, value: u32) -> Result<()> {
        debug!("set vga gain: {}", value);

        let mut value_16 = value as u16;
        if value_16 > 62 {
            return Err(HackRFError::ParamErr("vga >62".to_string()));
        }
        value_16 &= !0x01;

        let mut request = new_request(Cmd::SET_VGA_GAIN);
        request.index = value_16;
        let data = self.control_transfer_in(request, 1).await?;

        if data[0] == 0 {
            Err(HackRFError::ParamErr("vga set fail".to_string()))
        } else {
            Ok(())
        }
    }

    async fn set_amp_enable(&self, enable: bool) -> Result<()> {
        debug!("set amp enable: {}", enable);
        let value = enable as u16;
        let mut request = new_request(Cmd::AMP_ENABLE);
        request.value = value;
        self.control_transfer_out(request, vec![]).await
    }

    pub async fn amp_enable(&self) -> Result<()> {
        self.set_amp_enable(true).await
    }
    pub async fn amp_disable(&self) -> Result<()> {
        self.set_amp_enable(false).await
    }
}


#[cfg(test)]
mod tests {
    use std::time::{Duration, Instant};

    use futures::StreamExt;
    use log::{info, LevelFilter};
    use tokio::select;

    use super::*;

    fn init() {
        let _ = env_logger::builder().filter_level(LevelFilter::Debug).is_test(true).try_init();
    }

    #[tokio::test]
    async fn device_list() {
        init();


        let sdr = HackRF::device_list().await.unwrap();

        for one in sdr {
            info!("{:?}", one);
        }
    }

    #[tokio::test]
    async fn open_by_sn() {
        init();


        let sdr = HackRF::open_one().await.unwrap();
        let sn = sdr.sn().unwrap();
        drop(sdr);
        info!("sn: {}", sn);

        let sdr = HackRF::open_by_sn(sn).await.unwrap();
        info!("open sn ok: {}", sdr.sn().unwrap());
    }

    #[tokio::test]
    async fn set_transceiver_mode() {
        init();


        let sdr = HackRF::open_one().await.unwrap();

        sdr.set_transceiver_mode(TransceiverMode::OFF).await.unwrap();

        info!("finish");
    }


    #[tokio::test]
    async fn version_string() {
        init();


        let sdr = HackRF::open_one().await.unwrap();

        let version = sdr.version_string_read(30).await.unwrap();

        let version = String::from_utf8(version).unwrap();

        info!("version: {}", version);
    }

    #[tokio::test]
    async fn set_bandwidth() {
        init();

        let sdr = HackRF::open_one().await.unwrap();
        sdr.set_baseband_filter_bandwidth(25_000_000).await.unwrap();
    }

    #[tokio::test]
    async fn set_sample_rate() {
        init();

        let sdr = HackRF::open_one().await.unwrap();

        info!("{:?}", sdr);

        sdr.set_sample_rate(20e6).await.unwrap();
    }

    #[tokio::test]
    async fn set_freq() {
        init();


        let sdr = HackRF::open_one().await.unwrap();

        info!("{:?}", sdr);

        sdr.set_freq(88.7e6).await.unwrap();
    }

    #[tokio::test]
    async fn set_lna_gain() {
        init();


        let sdr = HackRF::open_one().await.unwrap();

        sdr.set_lna_gain(38).await.unwrap();
    }

    #[tokio::test]
    async fn set_vga_gain() {
        init();


        let sdr = HackRF::open_one().await.unwrap();

        sdr.set_vga_gain(24).await.unwrap();
    }

    #[tokio::test]
    async fn rx_data() {
        init();


        let sdr = HackRF::open_one().await.unwrap();

        let start = Instant::now();
        sdr.amp_enable().await.unwrap();
        sdr.set_vga_gain(24).await.unwrap();
        sdr.set_lna_gain(24).await.unwrap();
        sdr.set_freq(400e6).await.unwrap();
        sdr.set_sample_rate(20e6).await.unwrap();
        let duration = Instant::now().duration_since(start);

        info!("指令时间：{:?}", duration);


        let mut rx = sdr.start_rx_channel(PipConfig {
            cache_size: 30,
            request_num: 4,
            ..Default::default()
        }).await.unwrap();

        let (stop_tx, mut stop_rx) = tokio::sync::oneshot::channel();


        tokio::spawn(async move {
            let mut all = 0usize;
            let start = Instant::now();


            loop {
                select! {
                    res = rx.next() => {
                        match &res{
                            Some(r)=> {
                                 all += r.len();
                            }
                            None=>break,
                        }
                    }
                    _ = (&mut stop_rx) => {
                        break;
                    }
                }
            }
            let duration = Instant::now().duration_since(start);
            let bits = (all) as f64;
            let seconds = duration.as_secs_f64();
            let mb = (bits / seconds) / 1_000_000.0;

            info!("速度：{}", mb);
            info!("接收停止");
        });


        tokio::time::sleep(Duration::from_secs(5)).await;
        info!("send stop");
        stop_tx.send(1).unwrap();
        tokio::time::sleep(Duration::from_secs(1)).await;
        info!("finish");
    }
}
